'''
- "app.py" 文件是一个文档扫描仪应用程序的主要入口点。
- 它提供了一个可视化的用户界面，用于加载图片、调整文档角落位置、裁剪文档并显示结果。
- 它的作用是提供一个简单易用的界面，使用户能够方便地进行文档扫描操作。
'''

import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
import cv2 as cv
from doc_scanner import DocScanner
import numpy as np


class DocScannerApp:
    def __init__(self):
        self.doc_scanner = DocScanner()
        self.corners = None
        self.dragging_idx = -1
        self.img = None
        self.root = tk.Tk()
        self.canvas = tk.Canvas(self.root, width=600, height=400)
        self.canvas.pack()

        self.canvas.bind("<Button-1>", self.mouse_callback)
        self.canvas.bind("<ButtonRelease-1>", self.mouse_callback)
        self.canvas.bind("<B1-Motion>", self.mouse_callback)

        btn_select = tk.Button(self.root, text="Select Image", command=self.select_image)
        btn_select.pack(side=tk.LEFT)

        self.show_mouse_move = tk.BooleanVar()
        chk_show_mouse_move = tk.Checkbutton(self.root, text="Show Mouse Move", variable=self.show_mouse_move)
        chk_show_mouse_move.pack(side=tk.LEFT)

        btn_crop = tk.Button(self.root, text="Crop", command=self.crop)
        btn_crop.pack(side=tk.RIGHT)

    def select_image(self):
        file_path = filedialog.askopenfilename()
        if not file_path:  # 检查文件路径是否为空
            return
        try:
            self.img, self.corners = self.doc_scanner.load_image(file_path)
            # 确保图像尺寸不会超过画布的初始尺寸
            img_height, img_width, _ = self.img.shape
            if img_height > 600 or img_width > 800:
                scale = min(600 / max(img_height, img_width), 800 / max(img_height, img_width))
                self.img = cv.resize(self.img, None, fx=scale, fy=scale)
                self.corners = self.corners * scale
            # 更新画布尺寸以适应图像
            self.canvas.config(width=img_width, height=img_height)
            self.root.geometry(f"{img_width+50}x{img_height+50}")
            self.redraw()
        except ValueError as e:
            print("发生错误：", e)  # 打印出加载图像时的错误信息
    def mouse_callback(self, event):
        x, y = event.x, event.y
        if event.type == '<Button-1>':
            print(f"鼠标在({x},{y})按下")
            for idx, corner in enumerate(self.corners):
                if np.linalg.norm(np.array([x, y])-corner) < 10:
                    self.dragging_idx = idx
                    print(f"要开始拖动角落: corners[{idx}]={corner} , 所以变量: dragging_idx 被设置为 {idx}")
                    break
        elif event.type == '<ButtonRelease-1>':
            print(f"鼠标在({x},{y})释放")
            self.dragging_idx = -1
        elif event.type == '<B1-Motion>':
            if self.show_mouse_move.get():
                print(f"鼠标在({x},{y})移动")
            if self.dragging_idx != -1:
                self.corners[self.dragging_idx] = [x, y]
                self.redraw()

    def redraw(self):
        img_copy = self.img.copy()
        for idx, corner in enumerate(self.corners):
            cv.circle(img_copy, (int(corner[0]), int(corner[1])), 5, (0, 255, 0), -1)
        cv.polylines(img_copy, [np.int32([self.corners])], isClosed=True, color=(0, 255, 0), thickness=2)
        img_tk = self.cv2image_to_tkinter_image(img_copy)
        self.canvas.create_image(0, 0, anchor=tk.NW, image=img_tk)
        self.canvas.image = img_tk

    def cv2image_to_tkinter_image(self, cv2_image):
        cv2_image_rgb = cv.cvtColor(cv2_image, cv.COLOR_BGR2RGB)
        pil_image = Image.fromarray(cv2_image_rgb)
        return ImageTk.PhotoImage(pil_image)

    def crop(self):
        cropped_img = self.doc_scanner.crop_image(self.img, self.corners)
        cropped_img_tk = self.cv2image_to_tkinter_image(cropped_img)
        cropped_image_window = tk.Toplevel(self.root)
        cropped_image_window.title("Cropped Image")
        img_label = tk.Label(cropped_image_window, image=cropped_img_tk)
        img_label.pack()
        btn_close = tk.Button(cropped_image_window, text="Close", command=cropped_image_window.destroy)
        btn_close.pack()
        img_label.image = cropped_img_tk

    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    app = DocScannerApp()
    app.run()
    